
public class Box extends Primitive{
	
	private Vector[] p = null;
	private Rectangle[] edges = null;
	//private static int dbgCounter = 0;
	
	public Box(){
		this.p = new Vector[4];
		this.edges = new Rectangle[6];
		for (int i=0; i<4; i++){
			this.p[i] = new Vector();
		}
		for (int i=0; i<6; i++){
			this.edges[i] = new Rectangle();
		}
		this.setSurface(new Surface());
	}
	
	public Box(Vector v0, Vector v1, Vector v2, Vector v3){
		this();
		this.p[0] = v0;
		this.p[1] = v1;
		this.p[2] = v2;
		this.p[3] = v3;
		Vector other0 = Vector.add(v1 ,
								Vector.add(Vector.sub(v2, v0) , Vector.sub(v3, v0)));
		Vector other1 = Vector.add(other0, Vector.sub(v1, v0).mul(-1));
		Vector other2 = Vector.add(other0, Vector.sub(v2, v0).mul(-1));
		Vector other3 = Vector.add(other0, Vector.sub(v3, v0).mul(-1));
		this.edges[0] = new Rectangle(v0,v1,v2);
		this.edges[1] = new Rectangle(v0,v1,v3);
		this.edges[2] = new Rectangle(v0,v2,v3);
		this.edges[3] = new Rectangle(other0,other1,other2);
		this.edges[4] = new Rectangle(other0,other1,other3);
		this.edges[5] = new Rectangle(other0,other2,other3);
	}
	
	public Box(Vector v0, Vector v1, Vector v2, Vector v3, Surface surface){
		this(v0, v1, v2, v3);
		this.setSurface(surface);
	}
	
	public Box( Vector[] args){
		this(args[0],args[1],args[2],args[3]);
	}
	
	public Box( Vector[] args, Surface surface){
		this(args);
		this.setSurface(surface);
	}
	
	public void setP(Vector[] p){
		this.p = p;
		this.updateAll();
	}

	public Vector[] getP(){
		return this.p;
	}

	public void setP0(Vector p0) {
		this.p[0]=p0;
		this.updateAll();
	}
	
	public Vector getP0(){
 		return this.p[0];
	}
	
	public void setP1(Vector p1) {
		this.p[1]=p1;
		this.updateAll();
	}
	
	public Vector getP1(){
		return this.p[1];
	}
	
	public void setP2(Vector p2) {
		this.p[2]=p2;
		this.updateAll();
	}
	
	public Vector getP2(){
		return this.p[2];
	}

	public void setP3(Vector p3) {
		this.p[3]=p3;
		this.updateAll();
	}
	
	public Vector getP3(){
		return this.p[3];
	}

	public void updateAll(){
		Vector other0 = Vector.add(this.p[1] ,
				Vector.add(Vector.sub(this.p[2], this.p[0]) , Vector.sub(this.p[3], this.p[0])));
		Vector other1 = Vector.add(other0, Vector.sub(this.p[1], this.p[0]).mul(-1));
		Vector other2 = Vector.add(other0, Vector.sub(this.p[2], this.p[0]).mul(-1));
		Vector other3 = Vector.add(other0, Vector.sub(this.p[3], this.p[0]).mul(-1));
		this.edges[0] = new Rectangle(this.p[0],this.p[1],this.p[2]);
		this.edges[1] = new Rectangle(this.p[0],this.p[1],this.p[3]);
		this.edges[2] = new Rectangle(this.p[0],this.p[2],this.p[3]);
		this.edges[3] = new Rectangle(other0,other1,other2);
		this.edges[4] = new Rectangle(other0,other1,other3);
		this.edges[5] = new Rectangle(other0,other2,other3);
		for ( int i=0; i< 6; i++){
			edges[i].updateNormal();
		}
	}

	public Vector intersectionPoint_direction(Vector source, Vector direction ){
		double minDistance = Double.MAX_VALUE;
		double dist;
		Vector closestPoint = null;
		Vector temp;
		for (int i=0; i<6; i++){
			temp = edges[i].intersectionPoint_direction(source, direction);
			if (temp == null) continue;
			dist = Vector.getDistance(temp, source);
			if (dist < minDistance){
				closestPoint = temp;
				minDistance = dist;
			}
		}
		return closestPoint;
	}

	@Override
	public Vector getNormalAt(Vector target, Vector viewDirection) {	
		/*System.out.println(dbgCounter);
		if (dbgCounter == 12107){
			System.out.println("brakPoint");
		}
		dbgCounter ++;*/
		
		double minDist = Double.MAX_VALUE;
		double dist;
		int closestIndex = 0;
		for (int i=0; i<6; i++){
			/*if (target.isInPlain(edges[i].getP()[0], edges[i].getNormal())){
				return edges[i].getNormalAt(target, viewDirection);
			}*/
			dist = target.distanceFromPlain(this.edges[i].getP0(), this.edges[i].getNormal());
			if (dist < minDist){
				minDist = dist;
				closestIndex = i;
			}
			
		}
		return this.edges[closestIndex].getNormalAt(target, viewDirection);
	}
	
	public static Box getDBGbox() {
		Vector v1 = new Vector(2,-2.25,-2);
		Vector v2 = new Vector(-2,-2.25,-2);
		Vector v3 = new Vector(2,-2.25,2);
		Vector v4 = new Vector(2,-2,-2);
		Box box = new Box(v1,v2,v3,v4);
		box.setMtlDiffuse(new RGB(0.6,0.6,0.6));
		box.setMtlAmbient(new RGB(0.6,0.6,0.6));
		return box;
	}
	
	public static Box getDBGbox2() {
		Vector v1 = new Vector(2,2,-2);
		Vector v2 = new Vector(-2,2,-2);
		Vector v3 = new Vector(2,2,2);
		Vector v4 = new Vector(2,2.25,-2);
		Box box = new Box(v1,v2,v3,v4);
		box.setMtlDiffuse(new RGB(0.6,0.6,0.6));
		box.setMtlAmbient(new RGB(0.6,0.6,0.6));
		return box;
	}

	@Override
	public Vector getLowestPoint() {
		double[] c0, c1, c2, c3, c4, c5, c6, c7;
		double[] ct = new double[3];
		Vector other0 = Vector.add(this.p[1] ,
				Vector.add(Vector.sub(this.p[2], this.p[0]) , Vector.sub(this.p[3], this.p[0])));
		Vector other1 = Vector.add(other0, Vector.sub(this.p[1], this.p[0]).mul(-1));
		Vector other2 = Vector.add(other0, Vector.sub(this.p[2], this.p[0]).mul(-1));
		Vector other3 = Vector.add(other0, Vector.sub(this.p[3], this.p[0]).mul(-1));
		c0 = p[0].getCoords();
		c1 = p[1].getCoords();
		c2 = p[2].getCoords();
		c3 = p[3].getCoords();
		c4 = other0.getCoords();
		c5 = other1.getCoords();
		c6 = other2.getCoords();
		c7 = other3.getCoords();
		for(int i=0; i<3; i++){
			ct[i] = Math.min(
						Math.min(Math.max(c0[i], c1[i]), Math.min(c2[i], c3[i])), 
						Math.min(Math.max(c4[i], c5[i]), Math.min(c6[i], c7[i])));
		}
		return new Vector(ct[0], ct[1], ct[2]);
	}

	@Override
	public Vector getHighestPoint() {
		double[] c0, c1, c2, c3, c4, c5, c6, c7;
		double[] ct = new double[3];
		Vector other0 = Vector.add(this.p[1] ,
				Vector.add(Vector.sub(this.p[2], this.p[0]) , Vector.sub(this.p[3], this.p[0])));
		Vector other1 = Vector.add(other0, Vector.sub(this.p[1], this.p[0]).mul(-1));
		Vector other2 = Vector.add(other0, Vector.sub(this.p[2], this.p[0]).mul(-1));
		Vector other3 = Vector.add(other0, Vector.sub(this.p[3], this.p[0]).mul(-1));
		c0 = p[0].getCoords();
		c1 = p[1].getCoords();
		c2 = p[2].getCoords();
		c3 = p[3].getCoords();
		c4 = other0.getCoords();
		c5 = other1.getCoords();
		c6 = other2.getCoords();
		c7 = other3.getCoords();
		for(int i=0; i<3; i++){
			ct[i] = Math.max(
						Math.max(Math.max(c0[i], c1[i]), Math.max(c2[i], c3[i])), 
						Math.max(Math.max(c4[i], c5[i]), Math.max(c6[i], c7[i])));
		}
		return new Vector(ct[0], ct[1], ct[2]);
	}
}
